package com.silence.gmall.handler;

import com.silence.gmall.base.Result;
import com.silence.gmall.enums.CommonCode;
import com.silence.gmall.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.ConversionNotSupportedException;
import org.springframework.beans.TypeMismatchException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.core.annotation.Order;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Method;
import java.sql.SQLException;
import java.util.List;
import java.util.Objects;
import java.util.StringJoiner;

/**
 * @Author silence
 * @Email 792245022@qq.com
 * @Date 2025-06-11 14:50
 * @Description 全局异常处理器
 */
@Slf4j
@Order(100)
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 参数校验全局异常处理
     *
     * @param e 拦截异常
     * @return 结果
     */
    @ExceptionHandler(value = {MethodArgumentNotValidException.class})
    public Result<Void> handleException(MethodArgumentNotValidException e) {
        log.error("参数校验异常：", e);
        // 获取所有异常信息
        List<ObjectError> allErrors = e.getBindingResult().getAllErrors();
        // 判断是否有错误信息
        if (CollectionUtils.isNotEmpty(allErrors)) {
            StringBuilder errorBuilder = new StringBuilder();
            StringJoiner sj = new StringJoiner(";");
            allErrors.forEach(item -> {
                FieldError fieldError = (FieldError) item;
                errorBuilder.append(fieldError.getDefaultMessage());
                sj.add(errorBuilder);
            });
            // 打印错误日志
            String errorMsg = sj.toString();
            // 获取方法信息
            Method method = e.getParameter().getMethod();
            if (Objects.nonNull(method)) {
                log.warn("{}.{} - 参数校验不通过：{}", method.getDeclaringClass().getName(), method.getName(), errorMsg);
            } else {
                log.warn("参数校验不通过：", e);
            }
            return Result.build(CommonCode.PARAM_IS_INVALID.getCode(), errorMsg);
        }
        log.warn("参数校验不通过，绑定结果中异常为空：", e);
        return Result.build(CommonCode.PARAM_IS_INVALID.getCode(), "参数校验异常，请检查参数");
    }

    /**
     * 业务异常
     *
     * @param ex 业务异常
     * @return 结果
     */
    @ExceptionHandler({ServiceException.class})
    public Result<Void> serviceExceptionHandler(ServiceException ex) {
        log.warn("业务异常：", ex);
        return Result.build(CommonCode.ERROR);
    }

    /**
     * 空指针异常
     *
     * @param ex 空指针异常
     * @return 结果
     */
    @ExceptionHandler({NullPointerException.class})
    public Result<Void> nullPointerExceptionHandler(NullPointerException ex) {
        log.warn("空指针异常：", ex);
        return Result.build(CommonCode.ERROR);
    }

    /**
     * 类型转换异常
     *
     * @param ex 类型转换异常
     * @return 结果
     */
    @ExceptionHandler({ClassCastException.class})
    public Result<Void> classCastExceptionHandler(ClassCastException ex) {
        log.warn("类型转换异常：", ex);
        return Result.build(CommonCode.ERROR);
    }

    /**
     * 文件未找到异常
     *
     * @param ex 文件未找到异常
     * @return 结果
     */
    @ExceptionHandler({FileNotFoundException.class})
    public Result<Void> fileNotFoundExceptionHandler(FileNotFoundException ex) {
        log.warn("文件未找到异常：", ex);
        return Result.build(CommonCode.ERROR);
    }

    /**
     * 数字格式异常
     *
     * @param ex 数字格式异常
     * @return 结果
     */
    @ExceptionHandler({NumberFormatException.class})
    public Result<Void> numberFormatExceptionHandler(NumberFormatException ex) {
        log.warn("数字格式异常：", ex);
        return Result.build(CommonCode.ERROR);
    }

    /**
     * 安全异常
     *
     * @param ex 安全异常
     * @return 结果
     */
    @ExceptionHandler({SecurityException.class})
    public Result<Void> securityExceptionHandler(SecurityException ex) {
        log.warn("安全异常：", ex);
        return Result.build(CommonCode.ERROR);
    }

    /**
     * SQL异常
     *
     * @param ex SQL异常
     * @return 结果
     */
    @ExceptionHandler({SQLException.class})
    public Result<Void> sqlExceptionHandler(SQLException ex) {
        log.warn("SQL异常：", ex);
        return Result.build(CommonCode.ERROR);
    }

    /**
     * 类型不存在异常
     *
     * @param ex 类型不存在异常
     * @return 结果
     */
    @ExceptionHandler({TypeNotPresentException.class})
    public Result<Void> typeNotPresentExceptionHandler(TypeNotPresentException ex) {
        log.warn("类型不存在异常：", ex);
        return Result.build(CommonCode.ERROR);
    }

    /**
     * IO异常
     *
     * @param ex IO异常
     * @return 结果
     */
    @ExceptionHandler({IOException.class})
    public Result<Void> ioExceptionHandler(IOException ex) {
        log.warn("IO异常：", ex);
        return Result.build(CommonCode.ERROR);
    }

    /**
     * 未知方法异常
     *
     * @param ex 未知方法异常
     * @return 结果
     */
    @ExceptionHandler({NoSuchMethodException.class})
    public Result<Void> noSuchMethodExceptionHandler(NoSuchMethodException ex) {
        log.warn("未知方法异常：", ex);
        return Result.build(CommonCode.ERROR);
    }

    /**
     * 数组越界异常
     *
     * @param ex 数组越界异常
     * @return 结果
     */
    @ExceptionHandler({IndexOutOfBoundsException.class})
    public Result<Void> indexOutOfBoundsExceptionHandler(IndexOutOfBoundsException ex) {
        log.warn("数组越界异常：", ex);
        return Result.build(CommonCode.ERROR);
    }

    /**
     * 无法注入实体异常
     *
     * @param ex 无法注入实体异常
     * @return 结果
     */
    @ExceptionHandler({NoSuchBeanDefinitionException.class})
    public Result<Void> noSuchBeanDefinitionExceptionHandler(NoSuchBeanDefinitionException ex) {
        log.warn("无法注入实体异常：", ex);
        return Result.build(CommonCode.ERROR);
    }

    /**
     * 消息体无法识别
     *
     * @param ex 消息体无法识别
     * @return 结果
     */
    @ExceptionHandler({HttpMessageNotReadableException.class})
    public Result<Void> requestNotReadableExceptionHandler(HttpMessageNotReadableException ex) {
        log.warn("消息体无法识别：", ex);
        return Result.build(CommonCode.ERROR);
    }

    /**
     * 类型不匹配异常
     *
     * @param ex 类型不匹配异常
     * @return 结果
     */
    @ExceptionHandler({TypeMismatchException.class})
    public Result<Void> typeMismatchExceptionHandler(TypeMismatchException ex) {
        log.warn("类型不匹配异常：", ex);
        return Result.build(CommonCode.ERROR);
    }

    /**
     * 不支持转换异常
     *
     * @param ex 不支持转换异常
     * @return 结果
     */
    @ExceptionHandler({ConversionNotSupportedException.class})
    public Result<Void> conversionNotSupportedExceptionHandler(RuntimeException ex) {
        log.warn("不支持转换异常：", ex);
        return Result.build(CommonCode.ERROR);
    }

    /**
     * HTTP消息不可写异常
     *
     * @param ex HTTP消息不可写异常
     * @return 结果
     */
    @ExceptionHandler({HttpMessageNotWritableException.class})
    public Result<Void> httpMessageNotWritableExceptionHandler(RuntimeException ex) {
        log.warn("HTTP消息不可写异常：", ex);
        return Result.build(CommonCode.ERROR);
    }

    /**
     * 算数异常
     *
     * @param ex 算数异常
     * @return 结果
     */
    @ExceptionHandler({ArithmeticException.class})
    public Result<Void> arithmeticExceptionHandler(ArithmeticException ex) {
        log.warn("算数异常：", ex);
        return Result.build(CommonCode.ERROR);
    }

    /**
     * 运行时异常
     *
     * @param ex 运行时异常
     * @return 结果
     */
    @ExceptionHandler({RuntimeException.class})
    public Result<Void> runtimeExceptionHandler(RuntimeException ex) {
        log.warn("运行时异常：", ex);
        return Result.build(CommonCode.ERROR);
    }

    /**
     * 参数校验全局异常处理
     *
     * @param e 拦截异常
     * @return 结果
     */
    @ExceptionHandler(value = {Exception.class})
    public Result<Void> handleException(Exception e) {
        log.error("系统异常：", e);
        return Result.build(CommonCode.ERROR);
    }
}
